from flask import current_app, jsonify
from flask import g
from flask import request
from flask import session
from info import constants, db
from info.models import User, News, Category, Comment, CommentLike
from info.utitls.common import user_login_data
from info.utitls.response_code import RET
from . import newsdetail_bp
from flask import render_template


# 127.0.0.1:5000/news/comment_like
@newsdetail_bp.route('/comment_like', methods=["POST", 'GET'])
@user_login_data
def comment_like():
    """点赞/取消点赞后端接口"""
    """
    1. 获取参数
        1.1 user:用户对象,comment_id:评论id, action:点赞和取消点赞的行为
    2. 校验参数
        2.1 非空判断
        2.2 action in ["add", "remove"]
    3. 逻辑处理
        3.0 comment_id查询出当前评论对象
        3.1 根据action行为点赞或者取消点赞
        点赞：创建 CommentLike 对象,将属性赋值
        取消点赞： CommentLik 对象从数据库删除
    4. 返回值
        登陆成功
    """
    # 1.1 user:用户对象,comment_id:评论id, action:点赞和取消点赞的行为
    user = g.user
    if not user:
        # 用户未登录
        current_app.logger.error("用户未登录")
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")

    param_dict = request.json
    comment_id = param_dict.get("comment_id")
    action = param_dict.get("action")

    # 2.1 非空判断
    if not all([comment_id, action]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不足")

    # 2.2 action in ["add", "remove"]
    if action not in ["add", "remove"]:
        current_app.logger.error("参数错误")
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")

    # 3.0 comment_id查询出当前评论对象
    try:
        comment = Comment.query.get(comment_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询评论对象异常")

    if not comment:
        return jsonify(errno=RET.NODATA, errmsg="评论不存在,不允许点赞")

    # 3.1 根据action行为点赞或者取消点赞
    if action == "add":

        comment_like = None
        try:
            # 查询当前用户对当前这条评论是否点过赞
            comment_like = CommentLike.query.filter(CommentLike.comment_id == comment_id,
                                                    CommentLike.user_id == user.id
                                                    ).first()
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg="查询评论点赞中间表对象异常")

        # 当前用户没有点过赞
        if not comment_like:
            # 点赞：创建 CommentLike 对象,将属性赋值
            comment_like_obj = CommentLike()
            # 当前用户点赞
            comment_like_obj.user_id = user.id
            # 当前用户评论点赞
            comment_like_obj.comment_id = comment_id
            # 评论对象的点赞数量累加
            comment.like_count += 1

            # 保存数据库
            db.session.add(comment_like_obj)

    else:
        # 取消点赞： CommentLik 对象从数据库删除
        comment_like = None
        try:
            # 查询当前用户对当前这条评论是否点过赞
            comment_like = CommentLike.query.filter(CommentLike.comment_id == comment_id,
                                                    CommentLike.user_id == user.id
                                                    ).first()
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg="查询评论点赞中间表对象异常")

        # 当前用户已经当前评论点过赞,才有资格取消点赞
        if comment_like:
            db.session.delete(comment_like)

            # 评论对象的点赞数量减1
            comment.like_count -= 1

    # 将上述点赞，取消点按的修改操作保存回数据库
    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        # 回滚
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="查询用户对象异常")

    # 4. 返回值
    return jsonify(errno=RET.OK, errmsg="OK")

# 127.0.0.1:5000/news/news_comment
@newsdetail_bp.route('/news_comment', methods=["POST"])
@user_login_data
def news_comment():
    """主评论/子评论后端接口"""
    """
    1. 获取参数
        1.1 user：当前登陆的用户,news_id:新闻id, comment:评论内容, parent_id:主评论id（非必传）
    2. 校验参数
        2.1 非空判断
    3. 逻辑处理
        3.0 根据news_id查询新闻对象（本身可以直接使用news_id给comment赋值,但是防止绕开前端发送请求的时候新闻不存在）
        3.1 创建评论模型
        3,2 保存到数据库
    4. 返回值
        登入成功
    """
    # 1.1 user：当前登陆的用户,news_id:新闻id, comment:评论内容, parent_id:主评论id（非必传）
    user = g.user
    if not user:
        # 用户未登陆
        current_app.logger.error("用户未登陆")
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")

    param_dict = request.json
    news_id = param_dict.get("news_id")
    comment_str = param_dict.get("comment")
    # 如果有值表示是子评论,反之就是主评论
    parent_id = param_dict.get("parent_id")

    # 2.1 非空判断
    if not all([news_id, comment_str]):
        current_app.logger.error("参数不足")
        return jsonify(errno=RET.PARAMERR, errmsg="参数不足")

    # 3.0 根据news_id查询新闻对象（本身可以直接使用news_id给comment赋值,但是防止绕开前端发送请求的时候新闻不存在）
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询新闻对象异常")

    if not news:
        return jsonify(errno=RET.NODATA, errmsg="新闻不存在,不能发表评论")

    # 3.1 创建评论模型,并给各个属性数值
    comment = Comment()
    # 哪个用户发表评论
    comment.user_id = user.id
    # 评论的哪条新闻
    comment.news_id = news.id
    # 评论内容
    comment.content = comment_str

    if parent_id:
        # 子评论
        comment.parent_id = parent_id

    # 3,2 保存到数据库
    try:
        db.session.add(comment)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        # 回滚
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="保存评论对象异常")

    # 4.返回值
    # 注意：评论完毕需要返回数据给前端显示
    return jsonify(errno=RET.OK, errmsg="OK", data=comment.to_dict())

# 127.0.0.1:5000/news/news_collect
@newsdetail_bp.route('/news_collect', methods=["POST"])
@user_login_data
def news_collect():
    """收藏/取消收藏的后端接口"""
    """
    1. 获取参数
        1.1 news_id:新闻id, user：当前登陆的用户对象, action：收藏,取消收藏的行为
    2. 校验处理
        2.1 非空判断
        2.2 约定action行为：action in ["collect", "cancel-collect"]
    3. 逻辑处理
        3.0 根据新闻id获取新闻对象
        3.1 根据action行为判断是否收藏
        收藏： 将新闻对象添加到用户收藏列表
        取消收藏： 将新闻对象从用户收藏列表中移除（前提：新闻已经在用户收藏列表中才能取消收藏）
        3.2 修改操作保存到数据库
    4. 返回值
        登陆成功
    """
    # 1.1 news_id:新闻id, user：当前登陆的用户对象, action：收藏,取消收藏的行为
    # 获取当前登陆的用户
    user = g.user

    if not user:
        # 用户未登陆
        current_app.logger.error("用户未登陆")
        return jsonify(errno=RET.SESSIONERR, errmsg="拥护未登录")

    params_dict = request.json
    news_id = params_dict.get("news_id")
    action = params_dict.get("action")

    # 2.1 非空判断
    if not all([news_id, action]):
        current_app.logger.error("参数不足")
        return jsonify(errno=RET.PARAMERR, errmsg="参数不足")

    # 2.2 约定action行为：action in ["collect", "cancel-collect"] 收藏/取消收藏
    if action not in ["collect", "cancel_collect"]:
        current_app.logger.error("参数错误")
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")

    # 3.0 根据新闻id获取新闻对象
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询新闻对象异常")

    if not news:
        return jsonify(errno=RET.NODATA, errmsg="新闻不存在")

    # 3.1 根据action行为判断是否收藏
    if action == "collect":
        # 收藏：将新闻对象添加到用户收藏列表
        user.collection_news.append(news)
    else:
        # 取消收藏： 将新闻对象从用户收藏列表中移除（前提：新闻已经在用户收藏列表中才能取消收藏）
        # 新闻在用户收藏列表中
        if news in user.collection_news:
            user.collection_news.remove(news)

    # 3.2 修改操作保存到数据库
    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        # 回滚
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="查询用户对象异常")

    # 4.返回值
    return jsonify(errno=RET.OK, errmsg="OK")


# 127.0.0.1/news/1     1:代表新闻id
@newsdetail_bp.route('/<int:news_id>')
@user_login_data
def get_news_detail(news_id):
    """展示新闻详情页面"""
    # ---------------1.查询用户登入信息,进行展示---------------------------------------------
    # 获取当前登录用户的user_id
    user = g.user

    # 将用户数据借助模板给前端展示
    # if user:
    #     user_dict = user.to_dict()

    # ---------------2.查询新闻点击排行数据---------------------------------------------
    try:
        news_rank_list = News.query.order_by(News.clicks.desc()).limit(constants.CLICK_RANK_MAX_NEWS)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询新闻数据异常")
    """
        将新闻对象列表 转换成 新闻字典列表
        news_rank_list ==> [news_obj, news_obj1, ...]   遍历拿出数据
        news_dict_list ==> [news_dict, news_dict1, ...]

            if news_rank_list:
                for news_obj in news_rank_list:
                    # 将新闻对象转换成字典
                    news_dict = news_obj.to_dict()
                    news_dict_list.append(news_dict)
    """
    news_dict_list = []
    for news_obj in news_rank_list if news_rank_list else []:
        # 将新闻对象转换成字典
        news_dict = news_obj.to_dict()
        news_dict_list.append(news_dict)

    # ---------------3.根据新闻id查询新闻数据---------------------------------------------
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询新闻对象异常")

    news_dict = None
    # 新闻对象转字典
    if news:
        news_dict = news.to_dict()

    # 标志当前用户是否收藏过该新闻。默认值：False表示没有收藏
    is_collected = False

    # 当前用户处于登入状态才查询是否收藏
    if user:
        # ---------------4.查询当前用户是否有收藏新闻--------------------------
        # 当前新闻是否在当前用户新闻收藏列表中
        if news in user.collection_news:
            is_collected = True

    # ---------------5.获取新闻评论列表数据--------------------------
    try:
        news_comment_list = Comment.query.filter(Comment.news_id == news_id)\
            .order_by(Comment.create_time.desc()).all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询用户对象异常")

    commentlike_id_list = []

    if user:
        # ---------------6.获取当前登陆用户具体对哪几天评论点过赞--------------------------
        # 1.查询除当前新闻的所有评论，取得所有评论的id ->  list[1, 2, 3, 4, 5, 6]
        # news_comment_list:评论对象列表  现将所有评论都拿到
        comment_id_list = [comment.id for comment in news_comment_list]  # news_comment_list 评论模型对象拿到了 每一个评论身上有一个id值

        # 2.在通过评论点赞模型(CommentLike)查询当前用户点赞了哪几条评论 -> [模型1, 模型2...】
        try:
            # commentLike_obj_list 评论点赞模型对象 过滤对哪几条评论点过赞
            # user_id == user.id 当前用户对比  点过赞的用户要跟当前登陆的用户进行id相等,才表示当前用户对哪几条评论点过赞 评论的id必须在整体的id范围内（comment_id_list）
            commentLike_obj_list = CommentLike.query.filter(CommentLike.comment_id.in_(comment_id_list),
                                     CommentLike.user_id == user.id).all()
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg="查询用户对象异常")

        # 3.遍历上一步的评论点赞模型列表,获取所有点赞过的评论id(comment_like.comment_id)
        # commentlike_id_list 评论点赞的一个对象, 对象里有一个评论comment_id
        commentlike_id_list = [commentlike_obj.comment_id for commentlike_obj in commentLike_obj_list]

    # 对象列表转字典列表
    comment_dict_list = []
    for comment_obj in news_comment_list if news_comment_list else []:
        # 评论对象转字典
        comment_dict = comment_obj.to_dict()
        comment_dict["is_like"] = False
        # 遍历每一个评论对象获取其id对比,看是否在评论点赞列表中
        # 如果 comment_obj1.id == 1  in [1, 3, 5] ==> is_like=True
        # 如果 comment_obj2.id == 2  in [1, 3, 5] ==> is_like=False
        # 如果 comment_obj3.id == 3  in [1, 3, 5] ==> is_like=True
        if comment_obj.id in commentlike_id_list:
            comment_dict["is_like"] = True
        comment_dict_list.append(comment_dict)

    # 首页数据字典
    data = {
        "user_info": user.to_dict() if user else None,
        "news_rank_list": news_dict_list,
        "news": news_dict,
        "is_collected": is_collected,
        "comments": comment_dict_list
    }
    return render_template("news/detail.html", data=data)
